﻿/**	@file		calc.h
 *	@date		(2011-10-18 21:29:12)/(2012-06-28 01:35:50)
 *-----------------------------------------------------------------------------
 *	@version	1.0.3.5
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/

#if			!defined(__LOLIX__SOLA__CALC__H__NICK__K_IN_G__)
#define		__LOLIX__SOLA__CALC__H__NICK__K_IN_G__

#if			!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
	#include	"../lolix_macro.h"
#endif	//	!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)

#if			!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)
	#include	"../lolix_type.h"
#endif	//	!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)

namespace lolix{namespace sola{
	template <typename _Ty>
	struct calc_sqrt
	{
		LOLIX_INLINE_CALL static _Ty invoke(_Ty v)
		{
			LOLIX_ASSERT(v >= 0, L"无效的数据");
			return sqrt(v);
		}
	};

	template <typename _Ty> struct calc_abs;
	template<> struct calc_abs<lx_i8>{LOLIX_INLINE_CALL static lx_i8 invoke(lx_i8 v){ return v - (v ^ (~(v>>7))); }};
	template<> struct calc_abs<lx_i16>{LOLIX_INLINE_CALL static lx_i16 invoke(lx_i16 v){ return v - (v ^ (~(v>>15))); }};
	template<> struct calc_abs<lx_i32>{LOLIX_INLINE_CALL static lx_i32 invoke(lx_i32 v){ return v - (v ^ (~(v>>31))); }};
	template<> struct calc_abs<lx_i64>{LOLIX_INLINE_CALL static lx_i64 invoke(lx_i64 v){ return v - (v ^ (~(v>>63))); }};
	template<> struct calc_abs<lx_f32>{LOLIX_INLINE_CALL static lx_f32 invoke(lx_f32 v){ lx_u32& uv = (lx_u32&)v;uv &= 0x7fffffff;return (lx_f32&)uv;}};
	template<> struct calc_abs<lx_f64>{LOLIX_INLINE_CALL static lx_f64 invoke(lx_f64 v){ lx_u32& uv = ((lx_u32*)&v)[1];uv &= 0x7fffffff;return (lx_f32&)uv;}};


	template <typename _Ty>
	struct calc_length
	{
		template<size_type _Dim>
		LOLIX_INLINE_CALL static _Ty invoke(const _Ty (&l)[_Dim], const _Ty (&r)[_Dim])
		{
			_Ty ty(0);
			for ( int i = 0; i != _Dim; ++i )
				ty += l[i]*l[i] + r[i]*r[i];
			return calc_sqrt<_Ty>(ty);
		}
	};

	template<>
	struct calc_sqrt<lx_f32>
	{
		LOLIX_INLINE_CALL static lx_f32 invoke(lx_f32 v)
		{
			//1:8:23
			lx_u32 fv = *(lx_u32*)&v;
			LOLIX_ASSERT((fv & 0x7f800000) != 0x7f800000 && !(fv & 0x80000000), L"无效的数据");
			if ( fv == 0 )
				return 0.f;
			//;1011 1111 1011 1111 1111 1111 1111 1111
			fv = ((fv >> 1) & 0xbfafffff);
			lx_u32 f = (fv + 0x1f800000) & 0x7f800000;
			LOLIX_ASSERT( !(f & ~0x7f800000), L"数据错误");
			fv = (fv & 0x807fffff) | f;
			//0x7f8
			float x = *(float*)&fv;
			x = (x+v/x)*0.5f;
			x = (x+v/x)*0.5f;
			x = (x+v/x)*0.5f;
			x = (x+v/x)*0.5f;
			return x;
		}
	};

	template<>
	struct calc_sqrt<lx_f64>
	{
		LOLIX_INLINE_CALL static lx_f64 invoke(lx_f64 v)
		{
			//1:11:52
			lx_u64 fv = *(lx_u64*)&v;
#if			(LOLIX_CFG__SIZE_TYPE_BITS_SIZE != 64)
			lx_u32* fl = reinterpret_cast<lx_u32*>(&fv);
#endif	//	(LOLIX_CFG__SIZE_TYPE_BITS_SIZE != 64)
			lx_u32* fh = reinterpret_cast<lx_u32*>(&fv)+1;
			LOLIX_ASSERT((*fh & 0x7ff00000) != 0x7ff00000 && !(*fh & 0x80000000), L"无效的数据");
			if ( fv == 0 )
				return 0.0;

			//;1011 1111 1111 0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
#if			(LOLIX_CFG__SIZE_TYPE_BITS_SIZE == 64)
			fv = (fv >> 1) & 0xbff7ffffffffffff;
#else	//	(LOLIX_CFG__SIZE_TYPE_BITS_SIZE == 64)
			*fl = (*fl >> 1) & ((*fh & 1) << 31);
			*fh = (*fh >> 1) & 0xbff7ffff;
#endif	//	(LOLIX_CFG__SIZE_TYPE_BITS_SIZE == 64)

			lx_u32 f = (*fh + 0x1ff00000) & 0x7ff00000;
			LOLIX_ASSERT( !(f & ~0x7ff00000), L"数据错误");
			*fh = (*fh & 0x800fffff) | f;
			double x = *(double*)&fv;
			x = (x+v/x)*0.5;
			x = (x+v/x)*0.5;
			x = (x+v/x)*0.5;
			x = (x+v/x)*0.5;
			x = (x+v/x)*0.5;
			//x = (x+v/x)*0.5;
			//x = (x+v/x)*0.5;
			//x = (x+v/x)*0.5;
			return x;
		}
	};
}}
#endif	//	!defined(__LOLIX__SOLA__CALC__H__NICK__K_IN_G__)
